<style lang="scss" scoped>
.middle {
  border-right: 1px solid #ccc;
  border-left: 1px solid #ccc;
  height: calc(100vh - 60px);
  .iphone {
    width: 375px;
    height: 667px;
    border: 1px #ccc solid;
    margin: 50px auto;
    position: relative;
  }
}

.leftContent {
  height: calc(100vh - 58px);
  overflow-y: scroll;
}
</style>

<template>
  <div>
    <my-header></my-header>
    <div>
      <el-row>
        <el-col :span="8">
          <el-tabs tab-position="left" class="demo-tabs">
            <el-tab-pane label="模板">User</el-tab-pane>
            <el-tab-pane label="文字">
              <h2
                style="text-align: center; line-height: 50px; height: 50px"
                v-for="(v, i) in textData"
                :key="i"
              >
                <span @click="addTextComponent(v)">{{ v.name }}</span>
              </h2>
            </el-tab-pane>
            <el-tab-pane label="图片">
              <div class="leftContent">
                <div>
                  <el-button type="primary" @click="uploadImage">上传图片</el-button>
                </div>
                <div>
                  <h2>素材列表</h2>
                  <el-row>
                    <el-col :span="12" v-for="(v, i) in images" :key="i" style="padding: 10px">
                      <img
                        width="100%"
                        height="200"
                        style="object-fit: cover"
                        :src="v"
                        alt=""
                        @click="addImageMiddle(v)"
                        @dragstart="handleDragStart(v, $event)"
                      />
                    </el-col>
                  </el-row>
                </div>
              </div>
            </el-tab-pane>
            <el-tab-pane label="上传">
              <div class="leftContent">
                <ul>
                  <li>1</li>
                  <li>2</li>
                  <li>3</li>
                  <li>4</li>
                  <li>5</li>
                  <li>6</li>
                  <li>7</li>
                  <li>8</li>
                  <li>9</li>
                  <li>10</li>
                  <li>11</li>
                  <li>12</li>
                  <li>13</li>
                  <li>14</li>
                  <li>15</li>
                  <li>16</li>
                  <li>17</li>
                  <li>18</li>
                  <li>19</li>
                  <li>20</li>
                  <li>21</li>
                  <li>22</li>
                  <li>23</li>
                  <li>24</li>
                  <li>25</li>
                  <li>26</li>
                  <li>27</li>
                  <li>28</li>
                  <li>29</li>
                  <li>30</li>
                  <li>31</li>
                  <li>32</li>
                  <li>33</li>
                  <li>34</li>
                  <li>35</li>
                  <li>36</li>
                  <li>37</li>
                  <li>38</li>
                  <li>39</li>
                  <li>40</li>
                  <li>41</li>
                  <li>42</li>
                  <li>43</li>
                  <li>44</li>
                  <li>45</li>
                  <li>46</li>
                  <li>47</li>
                  <li>48</li>
                  <li>49</li>
                  <li>50</li>
                  <li>51</li>
                  <li>52</li>
                  <li>53</li>
                  <li>54</li>
                  <li>55</li>
                  <li>56</li>
                  <li>57</li>
                  <li>58</li>
                  <li>59</li>
                  <li>60</li>
                  <li>61</li>
                  <li>62</li>
                  <li>63</li>
                  <li>64</li>
                  <li>65</li>
                  <li>66</li>
                  <li>67</li>
                  <li>68</li>
                  <li>69</li>
                  <li>70</li>
                  <li>71</li>
                  <li>72</li>
                  <li>73</li>
                  <li>74</li>
                  <li>75</li>
                  <li>76</li>
                  <li>77</li>
                  <li>78</li>
                  <li>79</li>
                  <li>80</li>
                  <li>81</li>
                  <li>82</li>
                  <li>83</li>
                  <li>84</li>
                  <li>85</li>
                  <li>86</li>
                  <li>87</li>
                  <li>88</li>
                  <li>89</li>
                  <li>90</li>
                  <li>91</li>
                  <li>92</li>
                  <li>93</li>
                  <li>94</li>
                  <li>95</li>
                  <li>96</li>
                  <li>97</li>
                  <li>98</li>
                  <li>99</li>
                  <li>100</li>
                </ul>
              </div>
            </el-tab-pane>
          </el-tabs>
        </el-col>
        <el-col :span="8" class="middle">
          <div style="display: flex; justify-content: center; align-items: center; height: 100px">
            <el-button type="primary" @click="handlePublic">{{ id ? '修改' : '发布' }}</el-button>
            <el-button type="info" @click="handlePreview">预览</el-button>
          </div>
          <div
            class="iphone"
            ref="iphoneRef"
            :style="backgroundStyle"
            @drop="handleDrop"
            @dragover.prevent.stop
          >
            <Vue3DraggableResizable
              :initW="v.style.width"
              :initH="v.style.height"
              v-model:x="v.style.left"
              v-model:y="v.style.top"
              v-model:w="v.style.width"
              v-model:h="v.style.height"
              :draggable="true"
              :resizable="true"
              v-for="v in middleData"
              :key="v.id"
            >
              <component
                :is="v.component"
                :style="v.style"
                @click="handleSelect(v)"
                :value="v.value"
              ></component>
            </Vue3DraggableResizable>
            <!-- 动态组件 -->
          </div>
        </el-col>
        <el-col :span="8">
          <el-tabs tab-position="top" style="height: 200px" class="demo-tabs">
            <el-tab-pane label="背景">
              <div style="padding: 10px">
                <el-form>
                  <!-- 区分区间类型 -->
                  <el-form-item label="背景颜色">
                    <el-input v-model="backgroundStyle.backgroundColor" type="color"></el-input>
                  </el-form-item>
                  <el-form-item label="背景图片">
                    <el-input v-model="backgroundStyle.backgroundImage" type="text"></el-input>
                  </el-form-item>
                </el-form>
                {{ backgroundStyle }}
              </div>
            </el-tab-pane>
            <el-tab-pane label="图层">
              <ul>
                <li
                  v-for="v in middleData"
                  :key="v.id"
                  style="
                    display: flex;
                    justify-content: space-between;
                    align-items: center;
                    height: 40px;
                    padding: 10px;
                  "
                >
                  <span>{{ v.name }}-{{ v.id }}</span>
                  <span @click="deleteComponent(v)">X</span>
                </li>
              </ul>
            </el-tab-pane>
            <el-tab-pane label="样式">
              <div style="padding: 10px">
                <el-form label-width="100px">
                  <!-- 内容：区分区间类型 -->
                  <el-form-item label="内容:" v-if="selectedData.type === 'text'">
                    <el-input v-model="selectedData.value"></el-input>
                  </el-form-item>
                  <el-form-item label="图片路径:" v-if="selectedData.type === 'image'">
                    <el-input v-model="selectedData.value"></el-input>
                  </el-form-item>

                  <!-- 样式 -->
                  <el-form-item
                    :key="key"
                    v-for="(value, key) in selectedData.style"
                    :label="styleKeyToChinese(key)"
                  >
                    <el-input
                      v-model="selectedData.style[key]"
                      :type="styleKeyToType(key)"
                      v-if="typeof value === 'number'"
                    ></el-input>
                    <el-input
                      v-model="selectedData.style[key]"
                      :type="styleKeyToType(key)"
                      v-else-if="typeof value === 'string'"
                    ></el-input>

                    <div v-else-if="typeof value === 'object'">
                      <div v-if="value.type === 'btn'">
                        <el-button
                          @click="value.value = v.value"
                          :type="value.value === v.value ? 'primary' : 'default'"
                          v-for="(v, i) in value.list"
                          :key="i"
                          >{{ v.label }}</el-button
                        >
                      </div>
                      <div v-else-if="value.type === 'select'">
                        <el-select v-model="value.value" style="width: 240px">
                          <el-option
                            v-for="(v, i) in value.list"
                            :key="i"
                            :label="v.label"
                            :value="v.value"
                          ></el-option>
                        </el-select>
                      </div>
                    </div>
                  </el-form-item>
                </el-form>
              </div>
            </el-tab-pane>
          </el-tabs>
        </el-col>
      </el-row>
    </div>

    <Preview :src="previewSrc" v-if="isShowPreview" @close="isShowPreview = false"></Preview>
  </div>
</template>

<script lang="ts" setup>
import { ref } from 'vue'
import { textData } from './text'
import type { LeftComponentState, MiddleComponentState } from '@/types'
import { cloneDeep } from 'lodash-es'
import { styleKeyToChinese, styleKeyToType } from '@/utils/asyncComponents'
import { createImageComponent } from './images'
import { client, client1 } from '@/config/aliOss'
import { ElMessage } from 'element-plus'
import Preview from '@/components/preview/indexView.vue'
import html2canvas from 'html2canvas'
import { useUserHooks } from '@/stores/user'
import axios from 'axios'
import { useRoute, useRouter } from 'vue-router'
import { map } from './map'

const { params } = useRoute()
const router = useRouter()
const id = params.id

// 脱拽参数
// 背景样式
const backgroundStyle = ref({
  backgroundColor: '#ffffff',
  backgroundImage: '',
  backgroundSize: '100% 100%'
})

// 中间所有数据
const middleData = ref<MiddleComponentState[]>([])
// 中间选中数据
const selectedData = ref<MiddleComponentState>({} as MiddleComponentState)
// 添加本文组件
const addTextComponent = (v: LeftComponentState) => {
  middleData.value.push(
    // 必须深度克隆， 这样数据才可以独立， 互不干扰
    cloneDeep({
      ...v,
      // 作为标识
      id: Math.random().toString().slice(2)
    })
  )
}
// 添加图片组件
const addImageMiddle = (url: string, x?: number, y?: number) => {
  const imageObject = createImageComponent(url, x, y)
  middleData.value.push(
    // 必须深度克隆， 这样数据才可以独立， 互不干扰
    cloneDeep({
      ...imageObject,
      // 作为标识
      id: Math.random().toString().slice(2)
    })
  )
}
const iphoneRef = ref<HTMLElement | null>(null)
const handleSelect = (v: MiddleComponentState) => {
  selectedData.value = v
  middleData.value.splice(
    middleData.value.findIndex((item) => item.id === v.id),
    1
  )
  middleData.value.push(v)
}
// 上传图片
const uploadImage = () => {
  const input = document.createElement('input')
  input.multiple = true
  input.type = 'file'
  input.click()
  input.addEventListener('change', async (e) => {
    if (input.files) {
      const files = [...input.files]
      if (!files.every((v) => v.type.includes('image')))
        return ElMessage({ type: 'error', message: '只可以上传图片' })

      if (files.length <= 0) return
      if (files.length > 9) return ElMessage({ type: 'error', message: '最多同时上传9张图拍呢' })

      // 上传
      await Promise.all(
        files.map((file) => {
          return client.put(Math.random() + file.name, file)
        })
      )
      await _getImages()
    }
  })
}

// 删除图层
const deleteComponent = (v: MiddleComponentState) => {
  middleData.value = middleData.value.filter((item) => item.id !== v.id)
}
const dragUrl = ref('')
const posDragEl = ref({ x: 0, y: 0 })
// 拖放松开
const handleDrop = (e) => {
  const pos = iphoneRef.value?.getBoundingClientRect()!
  const x = e.clientX - posDragEl.value.x - pos.left
  const y = e.clientY - posDragEl.value.y - pos.top
  addImageMiddle(dragUrl.value, x, y)
}

const handleDragStart = (url: string, e) => {
  dragUrl.value = url
  posDragEl.value = { x: e.offsetX, y: e.offsetY }
}
/**** 素材图片 */
const images = ref<string[]>([
  '/public/middle-banner.webp',
  'http://124.221.74.149:8010/images/banner1.webp',
  'http://2109a-wd.oss-cn-shanghai.aliyuncs.com/0.13878538190267121.jpg'
])

const _getImages = async () => {
  const resp = await client.list(null, {})
  const s = resp.objects.map((v) => v.url)
  images.value = s
}
_getImages()

/**** 预览 ****/
const isShowPreview = ref(false)
const previewSrc = ref('')
const handlePreview = () => {
  if (iphoneRef.value) {
    // 跨域
    html2canvas(iphoneRef.value, { useCORS: true }).then((canvas) => {
      const url = canvas.toDataURL()
      previewSrc.value = url
      isShowPreview.value = true
    })
  }
}

/**** 发布|修改 ****/
const handlePublic = async () => {
  if (middleData.value.length <= 0) {
    return ElMessage.error('未选中任何模块作品！！！')
  }
  if (iphoneRef.value) {
    // 跨域
    html2canvas(iphoneRef.value, { useCORS: true }).then(async (canvas) => {
      const url = canvas.toDataURL()
      var blob = dataURLtoBlob(url) // dataURL-> blob
      var file = blobToFile(blob, Math.random().toString() + '.jpg') // blob -> file
      // 上传到oss
      try {
        const aliResult = await client1.put(file.name, file)

        try {
          const productData = JSON.stringify({
            src: aliResult.url,
            data: middleData.value
          })
          const userId = useUserHooks().userInfo.id
          const aboutId = ''

          // 到底是编辑， 还是发布
          if (id) {
            // 编辑
            await axios.post('/product/' + id, {
              id: id,
              productData
            })
            ElMessage.success('修改成功, 2s之后进入我的作品')
          } else {
            // 发布
            await axios.put('/product', {
              productData,
              userId,
              aboutId
            })
            ElMessage.success('发布成功, 2s之后进入我的作品')
          }
          setTimeout(() => {
            router.push('/product/list')
          }, 2000)
        } catch (error) {
          ElMessage.error('服务器错误')
          console.log(error)
        }
      } catch (error) {
        ElMessage.error('阿里云上传图片出错')
        console.log(error)
      }

      //将base64转换为blob
      function dataURLtoBlob(dataurl) {
        var arr = dataurl.split(','),
          mime = arr[0].match(/:(.*?);/)[1],
          bstr = atob(arr[1]),
          n = bstr.length,
          u8arr = new Uint8Array(n)
        while (n--) {
          u8arr[n] = bstr.charCodeAt(n)
        }
        return new Blob([u8arr], { type: mime })
      }
      //将blob转换为file
      function blobToFile(theBlob, fileName) {
        theBlob.lastModifiedDate = new Date()
        theBlob.name = fileName
        return theBlob
      }
    })
  }
}

/**** 编辑回显 ****/
const _getDetail = async () => {
  const resp = await axios.get('/product/' + id)
  // 获取详情数据
  const result = resp.data.data[0]
  // 转化json
  result.productData = JSON.parse(result.productData)
  // 处理 components
  result.productData.data.forEach((v) => {
    v.component = map[v.type]
  })
  middleData.value = result.productData.data
}

id && _getDetail()
</script>

<script lang="ts">
export default {
  name: 'createProduct'
}
</script>
